contents

CPU 컨텍스트에서 스레드(thread) 는 스케줄러에 의해 독립적으로 관리될 수 있는 가장 작은 단위의 프로그래밍된 명령어 시퀀스입니다. 이는 실행의 기본 단위입니다.

이를 자세히 이해하려면, 함께 작동하는 두 가지 관점, 즉 소프트웨어 스레드(운영체제에서 관리)와 하드웨어 스레드(CPU가 실제로 실행하는 것)를 살펴보아야 합니다.

비유: 바쁜 주방을 상상해 보세요.


1. 소프트웨어 스레드 (운영체제 관점) 📜

프로그래머가 스레드를 생성한다고 말할 때, 이는 소프트웨어 스레드를 의미합니다. 이는 운영체제(OS)가 관리하는 개념입니다.

프로세스란?

먼저, 프로세스는 실행 중인 프로그램의 인스턴스입니다. 자체적인 비공개 메모리 공간, 파일 핸들 및 기타 리소스를 갖는 컨테이너입니다. 라자냐 요리책이 바로 프로세스입니다.

소프트웨어 스레드란?

스레드는 프로세스 내에서 실행되는 경로입니다. 단일 프로세스는 동시에 실행되는 여러 개의 스레드를 가질 수 있으며, 이들은 모두 동일한 목표를 향해 작동합니다. "소스를 만드는 단계"와 "파스타를 삶는 단계"는 "라자냐" 프로세스 내의 두 개의 별도 스레드가 될 수 있습니다.

스레드가 각자 가지는 것:

각 스레드는 다른 스레드와 공유하지 않는 자신만의 작은 리소스 집합을 가집니다.

스레드가 (같은 프로세스 내에서) 공유하는 것:

스레드는 대부분의 리소스를 동일한 프로세스 내의 다른 스레드와 공유하기 때문에 가볍습니다.

이러한 리소스 공유 덕분에 새 프로세스를 만드는 것보다 스레드를 만드는 것이 훨씬 빠르며, 스레드 간의 효율적인 통신이 가능합니다.


2. 하드웨어 스레드 (CPU 관점) 🧠

하드웨어 스레드는 명령어 스트림을 실행할 수 있는 CPU 상의 실제 물리적 리소스입니다. 하드웨어 스레드의 수는 CPU가 진정으로 동시에 할 수 있는 일의 양을 결정합니다.

싱글코어, 싱글 스레드 CPU (과거 방식):

하나의 코어를 가진 단순한 CPU는 한 번에 하나의 소프트웨어 스레드만 실행할 수 있었습니다. 여러 프로그램을 실행하기 위해 OS는 시분할(time-slicing) 을 사용했습니다. 즉, 여러 소프트웨어 스레드 사이를 빠르게 전환하며 각 스레드에 아주 작은 CPU 시간을 할당했습니다. 이는 멀티태스킹의 환상을 만들었지만, 실제로는 매 순간 오직 한 가지 일만 처리되고 있었습니다.

멀티코어 CPU:

이는 첫 번째 큰 도약이었습니다. 4개의 코어를 가진 CPU는 4개의 소프트웨어 스레드를 진정한 병렬로 실행할 수 있습니다. 네 명의 요리사가 각자 다른 작업을 동시에 할 수 있는 것과 같습니다.

동시적 멀티스레딩 (SMT) / 하이퍼스레딩:

"하드웨어 스레드"라는 용어가 가장 적절하게 사용되는 부분입니다. SMT는 하나의 물리적 CPU 코어가 운영체제에게 두 개(또는 그 이상)의 논리 코어로 보이게 하는 기술입니다. 인텔의 SMT 구현은 하이퍼스레딩(Hyper-Threading) 이라는 이름으로 유명합니다.

8개의 물리 코어와 하이퍼스레딩을 갖춘 CPU는 OS에게 16개의 논리 코어로 표시되며, 이는 OS가 16개의 소프트웨어 스레드를 동시에 실행하도록 스케줄링할 수 있음을 의미합니다.


모든 것이 함께 작동하는 방식

  1. 당신의 프로그램(프로세스)이 시작되고 여러 개의 소프트웨어 스레드를 생성합니다.
  2. 운영체제의 스케줄러는 실행 준비가 된 모든 프로세스의 모든 소프트웨어 스레드를 확인합니다.
  3. OS는 또한 CPU에서 사용 가능한 하드웨어 스레드(논리 코어)를 확인합니다.
  4. 스케줄러는 사용 가능한 하드웨어 스레드에 소프트웨어 스레드를 할당하여 실행합니다.
  5. 그러면 CPU 코어는 이 스레드들의 명령어를 실행하고, 하나가 멈출 때 SMT를 사용하여 다른 스레드로 전환함으로써 내부 구성 요소를 최대한 활용합니다.

요약하자면, "스레드"는 명령어의 흐름입니다. OS는 소프트웨어에서 스레드를 생성하고 관리하며, CPU는 이를 실행할 물리적인 하드웨어 리소스를 제공합니다. 현대 CPU는 SMT/하이퍼스레딩과 같은 기술을 사용하여 하나의 물리 코어가 두 개처럼 작동하게 함으로써, 더 많은 소프트웨어 스레드를 동시에 그리고 효율적으로 실행할 수 있도록 합니다.


하드웨어 스레드는 CPU 코어 내에서 명령어 시퀀스를 관리하고 실행할 수 있게 해주는 물리적 구성 요소입니다. CPU는 동시적 멀티스레딩(Simultaneous Multithreading, SMT) 이라는 기술을 사용하여 단일 코어에 여러 개의 하드웨어 스레드를 구현합니다. 인텔의 유명한 SMT 구현은 하이퍼스레딩(Hyper-Threading) 으로 알려져 있습니다.

이 기술은 하나의 물리 코어가 여러 개의 논리 코어처럼 작동하게 하여, 코어의 구성 요소들을 최대한 바쁘게 유지함으로써 효율성을 높이는 영리한 하드웨어 기법입니다.


문제점: 낭비되는 CPU 코어

현대의 CPU 코어는 여러 다른 스테이션(실행 유닛)을 가진 조립 라인처럼 매우 복잡합니다. 단일 소프트웨어 스레드만으로는 종종 이 모든 스테이션을 항상 바쁘게 유지할 수 없습니다. 이는 파이프라인 스톨(pipeline stall) 이라는 빈번하고 아주 작은 지연 때문입니다.

가장 흔한 원인은 캐시 미스(cache miss) 입니다. 스레드가 필요한 데이터가 CPU의 초고속 로컬 캐시에 없어 훨씬 느린 메인 메모리(RAM)에서 데이터가 도착하기를 기다려야 하는 상황입니다. 수백 클럭 사이클 동안 지속될 수 있는 이 대기 시간 동안, CPU 코어의 상당 부분이 유휴 상태가 되어 잠재적인 성능을 낭비하게 됩니다.

비유: 요리사(CPU 코어)가 레시피(소프트웨어 스레드)를 따르고 있습니다. 레시피에 "소금을 넣으시오"라고 되어 있지만, 소금이 지하실에 있습니다. 요리사는 모든 것을 멈추고 누군가 소금을 가져다줄 때까지 기다려야 합니다. 기다리는 동안 요리사의 손, 스토브, 도마는 모두 사용되지 않고 놀고 있습니다.


SMT 해결책: 두뇌는 복제하고, 손은 공유하라

SMT는 단일 물리 코어가 동시에 두 개 이상의 명령어 스트림(스레드)을 처리할 수 있게 합니다. 이는 스레드의 상태를 추적하는 부분은 복제하고, 실제 "작업을 하는" 부분은 공유함으로써 이를 달성합니다.

하나의 물리 코어가 2개의 하드웨어 스레드를 지원하기 위해 무엇이 복제되고 무엇이 공유되는지는 다음과 같습니다.

복제되는 부분 (하드웨어 스레드당 한 세트)

코어의 아키텍처 상태가 복제됩니다. 이는 각 스레드의 "두뇌" 또는 컨텍스트입니다.

공유되는 부분 (물리 코어당 한 세트)

비용이 많이 드는 실행 유닛은 공유됩니다. 이것이 조립 라인의 "손" 또는 "스테이션"입니다.


실제 작동 방식

  1. OS의 관점: 운영체제는 하나의 물리 코어를 보지 않습니다. 두 개의 논리 코어를 봅니다. 만약 2-way SMT(하이퍼스레딩) 기능이 있는 8코어 CPU가 있다면, OS는 16개의 프로세서가 있다고 보고합니다.
  2. 스케줄링: 16개의 프로세서가 있다고 생각하는 OS 스케줄러는 최대 16개의 다른 소프트웨어 스레드를 동시에 실행하도록 할당할 수 있습니다.
  3. 실행: OS가 스레드 A와 스레드 B를 단일 물리 코어의 두 하드웨어 스레드에 스케줄했다고 가정해 봅시다.
  4. 공백 메우기: 코어의 프론트엔드는 스레드 A와 스레드 B 모두로부터 명령어를 가져옵니다. 스레드 A가 명령어를 실행하다가 메모리에서 데이터를 기다려야 할 때(캐시 미스), 코어는 유휴 상태가 되지 않습니다. 즉시 스레드 B에서 준비된 명령어를 찾아 가용한 실행 유닛으로 보내 처리합니다.

비유 다시 보기: 요리사(코어)는 이제 두 개의 레시피(스레드 A와 스레드 B)를 동시에 추적하고 있습니다. 레시피 A에서 "물이 끓을 때까지 기다리시오"라는 지시가 나오면, 요리사의 두뇌(CPU 로직)는 즉시 비어있는 손(실행 유닛)에게 레시피 B의 단계, 예를 들어 "양파를 써시오"를 수행하라고 지시합니다. 요리사는 그냥 기다리는 대신 생산성을 유지하게 됩니다.

CPU가 2개 또는 4개의 스레드를 구현하는 방법

이것이 일반 소비자용 CPU에서 흔하지 않은 이유는 수확 체감(diminishing returns) 때문입니다. 1개에서 2개의 스레드로 가는 것은 가장 명백한 공백을 메워주어 상당한 향상을 제공합니다. 2개에서 4개로 가는 것은 모든 실행 유닛을 바쁘게 유지할 만큼 충분한 독립적인 명령어를 찾기가 더 어려워지기 때문에 추가적인 향상 폭이 더 작습니다. 또한 이는 하드웨어 복잡성을 증가시키고, 스레드들이 L1 캐시와 같은 공유 리소스를 두고 경쟁할 가능성(캐시 경합)을 높입니다.

요약하자면, 여러 하드웨어 스레드를 구현하는 것은 단일 물리 코어가 OS에게 여러 논리 코어처럼 보이게 하는 영리한 하드웨어 최적화입니다. 이는 코어의 비싼 실행 부분을 공유하고, 한 스레드가 불가피하게 멈출 때 생기는 공백을 다른 스레드의 명령어로 채움으로써 전반적인 CPU 활용도를 높여 더 나은 성능을 달성합니다.

references